package com.wonder.media;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;

import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class WonderPlayer extends Player{
	
	public static final int RENDER_OVERLAY = 1;
	public static final int RENDER_CANVAS = 0;
	
	private static WonderPlayer player = null;
	private ArrayList<PlayerEventListener> listeners = new ArrayList<PlayerEventListener>();
	private SurfaceHolder holder;
	private Surface surface;

	private int nAndroid;
	private static boolean  load_player = true;
	private boolean is_local = true;
	private String workspace;
	
	public static WonderPlayer getInstance(String workspace, boolean overlayUsed, int overlayFormat){
		load_player = true;
		if(player == null){
			player = new WonderPlayer(workspace);
		}
		if (load_player == false)
			return null;
		return player;
	}
	
	public static WonderPlayer getInstance(){
		return player;
	}
	
	private WonderPlayer(String workspace) {
		String AndroidVer;
		if(android.os.Build.VERSION.SDK_INT < 8){//8 means 2.2, it maybe not define in older version sdk, so use 8 replace FROYO constant
			AndroidVer = "21";
		} else{
			AndroidVer = android.os.Build.VERSION.RELEASE.substring(0, 3).replace(".", "");
		}
		nAndroid = 	Integer.parseInt(AndroidVer);
		String[] sLibs = { "libglib-wraps.so", "libplayback.so", "libwonderplayer-jni.so" };
		String[] sLibs_neon = { "libglib-wraps.so", "libplayback_neon.so", "libwonderplayer-jni-neon.so" };
		this.workspace = workspace;
		if(this.workspace != null)
		{
			if(this.workspace.endsWith("/") == false)
				this.workspace = this.workspace +"/";
			if (hasNeonInCpuFeatures()){
				for (String lib : sLibs_neon) {
					try{
						System.load(this.workspace+lib);
					}catch (Throwable e){
						load_player = false;
					}
				}
			}else{
				for (String lib : sLibs) {
					try{
						System.load(this.workspace+lib);
					}catch (Throwable e){
						load_player = false;
					}
				}
			}
			return ;
		}
	}
	
	public static boolean hasNeonInCpuFeatures()
	{
		ProcessBuilder cmd;
		boolean result = false;
		
		try {
			String[] args = {"/system/bin/cat", "/proc/cpuinfo"};
			cmd = new ProcessBuilder(args);
	
		   Process process = cmd.start();
		   InputStream in = process.getInputStream();
		   byte[] re = new byte[1024];
		   while(in.read(re) != -1){
			   String line = new String(re);
			   if (line.contains("Features")) {
				   result = line.contains("neon");
				   break;
			   }
		   }
		   in.close();
		} catch(IOException ex){
			ex.printStackTrace();
		}
		return result;
	}
	
	@Override
	public void destroy()
	{
		nDeInit();
		
		player = null;
	}
	
	@Override
	public boolean init(SurfaceView view, String SocketName,
			String httpUserAgent, int nFirmwareVersion, int nRenderType,
			int nVideoFormat, int nColorTab, int nAndroidVer) {
		// TODO Auto-generated method stub
		String AndroidModel = android.os.Build.MODEL;

		if(nRenderType == RENDER_OVERLAY)
		{
			if(AndroidModel.equalsIgnoreCase("MT810")||
					AndroidModel.equalsIgnoreCase("A6388")||
					AndroidModel.equalsIgnoreCase("A9188")||
					AndroidModel.equalsIgnoreCase("LT15i"))
			{
				nVideoFormat = 6;
				nColorTab = 0;
			}else if(AndroidModel.equalsIgnoreCase("OMAP_SS")||
					AndroidModel.equalsIgnoreCase("GT-I9008L"))
			{
				nVideoFormat = 4;
				nColorTab = 0;
			}
			else if(AndroidModel.equalsIgnoreCase("HTC Desire"))//not support this mobile by overlay mode
			{
				nRenderType = RENDER_CANVAS;
			}
		}
		if("".equals(SocketName)){
			SocketName = null;
		}

		holder = view.getHolder();
		surface = holder.getSurface();
		return nInit(this.workspace, SocketName, httpUserAgent, surface);
	}

	@Override
	public void start(String dataSource, int pos) {
		// TODO Auto-generated method stub
		try {
			System.out.println("fsjdfosdjfi");
			nStart(dataSource, pos);
		} catch (Exception e) {
			
		}
	}

	@Override
	public void seekTo(int sec) {
		// TODO Auto-generated method stub
		try {
			nSeekTo(sec);
		} catch (Exception e) {
			
		}
	}

	@Override
	public void play() {
		// TODO Auto-generated method stub
		try {
			nPlay();
		} catch (Exception e) {
			
		}
	}

	@Override
	public void pause() {
		// TODO Auto-generated method stub
		nPause();
	}

	@Override
	public void stop() {
		// TODO Auto-generated method stub
		try {
			nStop();
		} catch (Exception e) {
			
		}
	}

	@Override
	public void close() {
		// TODO Auto-generated method stub
		try {
			nDestroy();
		} catch (Exception e) {
			
		}
	}

	@Override
	public void suspend() {
		// TODO Auto-generated method stub
		try {
			nAVSuspend();
		} catch (Exception e) {
			
		}
	}

	@Override
	public void resume() {
		// TODO Auto-generated method stub
		try{
			nAVResume();
		} catch (Exception e) {
			
		}
	}

	@Override
	public void updateSurface(SurfaceHolder holder, int x, int y,
			int widthPixels, int heightPixels) {
		// TODO Auto-generated method stub
		if(holder == null){
			return;
		}
		this.holder = holder;
		surface = holder.getSurface();
		holder.setKeepScreenOn(true); 
		nUpdateSurface(x, y, widthPixels, heightPixels, holder.getSurface());
	}

	@Override
	public int getPassedSec() {
		// TODO Auto-generated method stub
//		Log.d(LOGTAG, "getPassedSec");
		return nGetPassedSec();
	}

	@Override
	public int getDuration() {
		// TODO Auto-generated method stub
//		Log.d(LOGTAG, "getDuration");
		return nGetDuration();
	}

	@Override
	public int getBufferPercentage() {
		// TODO Auto-generated method stub
		return nGetBufferPercentage();
	}

	@Override
	public int getPlayerStatus() {
		// TODO Auto-generated method stub
		return nGetPlayerStatus();
	}

	@Override
	public void addPlayerEventListener(PlayerEventListener listener) {
		// TODO Auto-generated method stub
		synchronized(this){
			if (!listeners.contains(listener))
				listeners.add(listener);
		}
	}

	@Override
	public void removePlayerEventListener(PlayerEventListener listener) {
		// TODO Auto-generated method stub
		synchronized(this){
			listeners.remove(listener);
		}
	}
	
	@SuppressWarnings("unchecked")
	private void notifyEvent(PlayerEvent event){
		ArrayList<PlayerEventListener> temp;
		synchronized(this){
			temp = (ArrayList<PlayerEventListener>)listeners.clone();
		}
		for(PlayerEventListener l:temp){
			l.postPlayerEvent(event);
		}
	}

	private void nativePlayerDurationUpdate(int duration) {
//		notifyEvent(new PlayerGetDurationEvent(PlayerEvent.PLAYER_EVENT_GET_DURATION, duration));	
	}
	private void nativePlayerStatusUpdate(int playerStatus) {
		notifyEvent(new PlayerStatusEvent(PlayerEvent.PLAYER_EVENT_STATUS, playerStatus));
	}

	private void nativePlayerVideoSizeUpdate(int width, int height){
		Log.d("libplayer", "width = " + width + " and height = " + height);
		notifyEvent(new PlayerVideoSizeEvent(PlayerEvent.PLAYER_EVENT_SIZE, width, height));
	}
	
	private void nativePlayerResolutionUpdate(int width, int height){
		Log.d("libplayer", "width = " + width + " and height = " + height);
		//notifyEvent(new PlayerVideoSizeEvent(PlayerEvent.PLAYER_EVENT_Resolution, width, height));
		notifyEvent(new PlayerVideoSizeEvent(PlayerEvent.PLAYER_EVENT_SIZE, width, height));
	}

	private void nativePlayerTimeUpdate(int time){
//		notifyEvent(new PlayerTimeEvent(PlayerEvent.PLAYER_EVENT_TIME, time));		
	}

	private void nativePlayerBufferPercentUpdate(int percent){
		notifyEvent(new PlayerBufferPercentEvent(PlayerEvent.PLAYER_EVENT_BUFFER, percent));
	}
	
	private native boolean nInit(String libPath, String netInterface, String httpUserAgent, Surface surface);

	private native void nStart(String dataSource, int pos );

	private native void nPlay();

	private native void nSeekTo(int mSec);

	private native void nPause();

	private native void nStop();

	private native int nGetPassedSec();

	private native int nGetDuration();

	private native int nGetBufferPercentage();

	private native int nGetPlayerStatus();

	private native void nDestroy();

	private native void nUpdateSurface(int x, int y, int widthPixels, int heightPixels, Surface surface);

	private native void nAVSuspend();

	private native void nAVResume();
	
	private native void nDeInit();
	
	private native int nGetheight();
	
	private native int nGetwidth();
	
	private native void nSetVideoMode(int videomode);

	@Override
	public void setVideoMode(int mode) {
		// TODO Auto-generated method stub
		nSetVideoMode(mode);
	}

	@Override
	public int getwidth() {
		// TODO Auto-generated method stub
		return nGetwidth();
	}

	@Override
	public int getheight() {
		// TODO Auto-generated method stub
		return nGetheight();
	}
}
